package org.jeecg.modules.device.listener;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zhouwr.common.constant.MqttTopics;
import com.zhouwr.common.device.vo.InstanceDataStructure;
import com.zhouwr.common.enums.DataRwAuthor;
import com.zhouwr.common.enums.ReportMode;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.alarm.service.IAlarmConfigService;
import org.jeecg.modules.device.entity.DeviceInstance;
import org.jeecg.modules.device.enums.DeviceInstanceState;
import org.jeecg.modules.device.listener.event.*;
import org.jeecg.modules.device.service.IDataReportService;
import org.jeecg.modules.device.service.IDeviceInstanceService;
import org.jeecg.modules.message.entity.MessageEvent;
import org.jeecg.modules.message.service.IMessageEventService;
import org.jeecg.modules.network.network.mqtt.IMqttSender;
import org.jeecg.modules.scene.service.ISceneService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @program: forallcn-iotps
 * @description:
 * @author: zhouwr
 * @create: 2020-12-07 12:43
 * @version：1.0
 **/
@Slf4j
@Component
public class MessageListener {
    private static MessageListener listener;
    @Autowired
    private ISceneService sceneService;
    @Resource
    private IMessageEventService eventService;
    @Resource
    private IDeviceInstanceService instanceService;
    @Resource
    private IDataReportService dataReportService;
    @Resource
    private IAlarmConfigService alarmConfigService;
    @Resource
    private IMqttSender mqttSender;

    @Async
    @EventListener(InstanceReceiveDataEvent.class)
    public void deviceStateUpdateEven(InstanceReceiveDataEvent event) {
        /* 检查执行告警 */
//        listener.alarmConfigService.queryTrigger(event.getInstanceId(), data);
        new Thread(() -> {
            /* 校验并构建数据节点的数据 */
            final JSONObject data = listener.dataReportService.verifyBuildDataNode(event.getInstanceId(), event.getDataMap());
            /* 按实例ID查询告警配置 */
            listener.alarmConfigService.queryByInstanceId(event.getInstanceId()).forEach(alarmConfig -> {
                /* 调用规则表达式 */
                if (listener.alarmConfigService.invokeTriggerRule(alarmConfig.getId(), data)) {
                    /* 保存数据 */
                    String reportDataId = listener.dataReportService.saveData(alarmConfig.getInstanceId(), data, ReportMode.REPORT);
                    /* 保存告警记录 */
                    listener.alarmConfigService.saveRecord(alarmConfig, data, reportDataId);
                    /* 满足调用规则表达式时，调用执行器（多个） */
                    listener.alarmConfigService.invokeActuators(alarmConfig.getId());
                }
            });
        }).start();

        new Thread(() -> {
            /* mqtt发送消息 */
            final List<InstanceDataStructure> dataStructures = listener.instanceService.buildInstanceDataCurrent(event.getInstanceId())
                    .stream()
                    .filter(instanceDataStructure -> instanceDataStructure.getRwAuthor().equals(DataRwAuthor.READ))
                    .collect(Collectors.toList());
            listener.mqttSender.sendToMqtt(MqttTopics.DATA_RECEIVE.getSceneTopic().apply(instanceService.getSceneId(event.getInstanceId())), JSON.toJSONString(dataStructures));
        }).start();
    }

    @Async
    @EventListener(InstanceNotFindEvent.class)
    public void deviceStateUpdateEven(InstanceNotFindEvent event) {
        log.info("{}, {}", event.getEventType().getName(), event);
        final DeviceInstance instance = listener.instanceService.getById(event.getInstanceId());
        final MessageEvent messageEvent = new MessageEvent(
                event.getInstanceId(),
                instance != null ? instance.getName() : "",
                event.getEventType(),
                0
        );
        listener.eventService.save(messageEvent);
    }

    @Async
    @EventListener(InstanceOnlineEvent.class)
    public void deviceStateUpdateEven(InstanceOnlineEvent event) {
        log.info("{}, {}", event.getEventType().getName(), event);
        final List<MessageEvent> messageEvents = listener.instanceService.getInstanceChildren(event.getInstanceId(), true)
                .stream()
                .map(deviceInstance -> {
                    final MessageEvent messageEvent = new MessageEvent(
                            deviceInstance.getId(),
                            deviceInstance.getName(),
                            event.getEventType(),
                            0
                    );
                    // mqtt发送消息
                    listener.mqttSender.sendToMqtt(MqttTopics.DEVICE_ONLINE.getSceneTopic().apply(instanceService.getSceneId(event.getInstanceId())), JSON.toJSONString(messageEvent));
                    return messageEvent;
                }).collect(Collectors.toList());
        listener.eventService.saveBatch(messageEvents);
        listener.instanceService.batchUpdateInstanceState(event.getInstanceId(), DeviceInstanceState.ONLINE);
    }

    @Async
    @EventListener(InstanceOfflineEvent.class)
    public void deviceStateUpdateEven(InstanceOfflineEvent event) {
        log.info("{}, {}", event.getEventType().getName(), event);
        final List<MessageEvent> messageEvents = listener.instanceService.getInstanceChildren(event.getInstanceId(), true)
                .stream()
                .map(deviceInstance -> {
                    final MessageEvent messageEvent = new MessageEvent(
                            deviceInstance.getId(),
                            deviceInstance.getName(),
                            event.getEventType(),
                            0
                    );
                    // mqtt发送消息
                    listener.mqttSender.sendToMqtt(MqttTopics.DEVICE_OFFLINE.getSceneTopic().apply(instanceService.getSceneId(event.getInstanceId())), JSON.toJSONString(messageEvent));
                    return messageEvent;
                }).collect(Collectors.toList());
        listener.eventService.saveBatch(messageEvents);
        listener.instanceService.batchUpdateInstanceState(event.getInstanceId(), DeviceInstanceState.OFFLINE);
    }

    @Async
    @EventListener(NetworkServerExceptionEvent.class)
    public void deviceStateUpdateEven(NetworkServerExceptionEvent event) {
        log.warn("{}, {}", event.getEventType().getName(), event);
        final MessageEvent messageEvent = new MessageEvent(
                event.getServerName(),
                event.getEventType(),
                0
        );
        listener.eventService.save(messageEvent);
    }

    @Async
    @EventListener(InstanceNotActionEvent.class)
    public void deviceStateUpdateEven(InstanceNotActionEvent event) {
        log.warn("{}, {}", event.getEventType().getName(), event);
        final MessageEvent messageEvent = new MessageEvent(
                event.getInstanceId(),
                event.getEventType(),
                0
        );
        listener.eventService.save(messageEvent);
    }

    /**
     * 初始化操作
     */
    @PostConstruct
    public void init() {
        listener = this;
        listener.alarmConfigService = this.alarmConfigService;
        listener.dataReportService = this.dataReportService;
        listener.eventService = this.eventService;
        listener.instanceService = this.instanceService;
        listener.mqttSender = this.mqttSender;
    }
}
